<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JSON解析器 - 在线测试工具</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            min-height: 100vh;
            padding: 20px;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            background: rgba(255, 255, 255, 0.95);
            border-radius: 20px;
            box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
            overflow: hidden;
        }

        .header {
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
            padding: 30px;
            text-align: center;
        }

        .header h1 {
            font-size: 2.5em;
            margin-bottom: 10px;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
        }

        .header p {
            font-size: 1.2em;
            opacity: 0.9;
        }

        .main-content {
            padding: 30px;
        }

        .input-section {
            margin-bottom: 30px;
        }

        .input-section h2 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.5em;
        }

        .input-group {
            margin-bottom: 20px;
        }

        .input-group label {
            display: block;
            font-weight: 600;
            color: #555;
            margin-bottom: 8px;
        }

        .json-input {
            width: 100%;
            height: 200px;
            padding: 15px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            resize: vertical;
            transition: border-color 0.3s ease;
        }

        .json-input:focus {
            outline: none;
            border-color: #4facfe;
            box-shadow: 0 0 0 3px rgba(79, 172, 254, 0.1);
        }

        .button-group {
            display: flex;
            gap: 15px;
            margin-bottom: 30px;
        }

        .btn {
            padding: 12px 24px;
            border: none;
            border-radius: 8px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            transition: all 0.3s ease;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }

        .btn-primary {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
        }

        .btn-primary:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
        }

        .btn-secondary {
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            color: white;
        }

        .btn-secondary:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 20px rgba(240, 147, 251, 0.4);
        }

        .btn-success {
            background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
            color: white;
        }

        .btn-success:hover {
            transform: translateY(-2px);
            box-shadow: 0 8px 20px rgba(79, 172, 254, 0.4);
        }

        .result-section {
            background: #f8f9fa;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 30px;
        }

        .result-section h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.3em;
        }

        .result-content {
            background: white;
            padding: 20px;
            border-radius: 8px;
            border: 1px solid #e0e0e0;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            max-height: 300px;
            overflow-y: auto;
            white-space: pre-wrap;
            word-wrap: break-word;
        }

        .error {
            color: #e74c3c;
            background: #fdf2f2;
            border-color: #fecaca;
        }

        .success {
            color: #27ae60;
            background: #f0f9f4;
            border-color: #c6f6d5;
        }

        .examples {
            background: #f8f9fa;
            border-radius: 12px;
            padding: 20px;
            margin-bottom: 30px;
        }

        .examples h3 {
            color: #333;
            margin-bottom: 15px;
            font-size: 1.3em;
        }

        .example-item {
            background: white;
            padding: 15px;
            margin-bottom: 10px;
            border-radius: 8px;
            border: 1px solid #e0e0e0;
            cursor: pointer;
            transition: all 0.3s ease;
        }

        .example-item:hover {
            background: #f0f8ff;
            border-color: #4facfe;
            transform: translateY(-2px);
        }

        .example-item strong {
            color: #333;
            display: block;
            margin-bottom: 5px;
        }

        .example-item code {
            background: #f1f3f4;
            padding: 2px 6px;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            color: #666;
        }

        .stats {
            display: flex;
            justify-content: space-around;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 20px;
            border-radius: 12px;
            margin-bottom: 30px;
        }

        .stat-item {
            text-align: center;
        }

        .stat-item .number {
            font-size: 2em;
            font-weight: bold;
            display: block;
        }

        .stat-item .label {
            font-size: 0.9em;
            opacity: 0.8;
        }

        .features {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }

        .feature-card {
            background: white;
            padding: 20px;
            border-radius: 12px;
            border: 1px solid #e0e0e0;
            text-align: center;
            transition: all 0.3s ease;
        }

        .feature-card:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
        }

        .feature-card .icon {
            font-size: 3em;
            margin-bottom: 15px;
        }

        .feature-card h4 {
            color: #333;
            margin-bottom: 10px;
            font-size: 1.2em;
        }

        .feature-card p {
            color: #666;
            font-size: 0.9em;
            line-height: 1.4;
        }

        @media (max-width: 768px) {
            .button-group {
                flex-direction: column;
            }
            
            .btn {
                width: 100%;
            }
            
            .stats {
                flex-direction: column;
                gap: 15px;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>🚀 JSON解析器</h1>
            <p>强大的在线JSON解析和验证工具</p>
        </div>

        <div class="main-content">
            <div class="stats">
                <div class="stat-item">
                    <span class="number" id="parseCount">0</span>
                    <span class="label">解析次数</span>
                </div>
                <div class="stat-item">
                    <span class="number" id="successCount">0</span>
                    <span class="label">成功解析</span>
                </div>
                <div class="stat-item">
                    <span class="number" id="errorCount">0</span>
                    <span class="label">错误次数</span>
                </div>
            </div>

            <div class="features">
                <div class="feature-card">
                    <div class="icon">⚡</div>
                    <h4>高性能解析</h4>
                    <p>逐字符解析，内存高效，支持大型JSON文件</p>
                </div>
                <div class="feature-card">
                    <div class="icon">🔍</div>
                    <h4>精确错误定位</h4>
                    <p>准确定位错误位置，提供详细的错误信息</p>
                </div>
                <div class="feature-card">
                    <div class="icon">🌍</div>
                    <h4>完整Unicode支持</h4>
                    <p>支持中文、表情符号和所有Unicode字符</p>
                </div>
                <div class="feature-card">
                    <div class="icon">📋</div>
                    <h4>标准JSON规范</h4>
                    <p>严格遵循JSON规范，支持所有标准数据类型</p>
                </div>
            </div>

            <div class="input-section">
                <h2>💻 JSON输入</h2>
                <div class="input-group">
                    <label for="jsonInput">在下方输入或粘贴您的JSON数据：</label>
                    <textarea id="jsonInput" class="json-input" placeholder='输入JSON数据，例如：
{
    "name": "张三",
    "age": 25,
    "active": true,
    "hobbies": ["读书", "运动", "编程"],
    "address": {
        "city": "北京",
        "zipCode": "100000"
    }
}'></textarea>
                </div>
                
                <div class="button-group">
                    <button class="btn btn-primary" onclick="parseJSON()">🔍 解析JSON</button>
                    <button class="btn btn-secondary" onclick="clearAll()">🗑️ 清空</button>
                    <button class="btn btn-success" onclick="formatJSON()">✨ 格式化</button>
                </div>
            </div>

            <div class="result-section">
                <h3>📊 解析结果</h3>
                <div id="result" class="result-content">等待解析...</div>
            </div>

            <div class="examples">
                <h3>📚 示例数据</h3>
                <div class="example-item" onclick="loadExample(0)">
                    <strong>基本对象</strong>
                    <code>{"name": "张三", "age": 25, "active": true}</code>
                </div>
                <div class="example-item" onclick="loadExample(1)">
                    <strong>数组数据</strong>
                    <code>[1, 2, 3, "hello", true, null]</code>
                </div>
                <div class="example-item" onclick="loadExample(2)">
                    <strong>嵌套结构</strong>
                    <code>{"users": [{"name": "Alice"}, {"name": "Bob"}]}</code>
                </div>
                <div class="example-item" onclick="loadExample(3)">
                    <strong>复杂数据</strong>
                    <code>包含产品信息、价格、规格等复杂嵌套数据</code>
                </div>
                <div class="example-item" onclick="loadExample(4)">
                    <strong>Unicode字符</strong>
                    <code>{"message": "你好世界 🌍", "emoji": "😊"}</code>
                </div>
            </div>
        </div>
    </div>

    <script>
        // JSON解析器错误类
        class JSONParseError extends Error {
            constructor(message, position = -1) {
                super(`JSON解析错误 (位置 ${position}): ${message}`);
                this.name = 'JSONParseError';
                this.message = message;
                this.position = position;
            }
        }

        // JSON解析器主类
        class JSONParser {
            constructor() {
                this.text = '';
                this.pos = 0;
                this.length = 0;
            }

            parse(text) {
                this.text = text.trim();
                this.pos = 0;
                this.length = this.text.length;

                if (!this.text) {
                    throw new JSONParseError('空的JSON字符串', 0);
                }

                try {
                    const result = this._parseValue();
                    this._skipWhitespace();

                    if (this.pos < this.length) {
                        throw new JSONParseError('JSON字符串后有多余字符', this.pos);
                    }

                    return result;
                } catch (error) {
                    if (error instanceof JSONParseError) {
                        throw error;
                    }
                    throw new JSONParseError('JSON字符串意外结束', this.pos);
                }
            }

            _currentChar() {
                if (this.pos >= this.length) {
                    throw new JSONParseError('字符串意外结束', this.pos);
                }
                return this.text[this.pos];
            }

            _advance() {
                const char = this._currentChar();
                this.pos++;
                return char;
            }

            _skipWhitespace() {
                while (this.pos < this.length && /\s/.test(this.text[this.pos])) {
                    this.pos++;
                }
            }

            _parseValue() {
                this._skipWhitespace();

                if (this.pos >= this.length) {
                    throw new JSONParseError('期望值但遇到字符串结束', this.pos);
                }

                const char = this._currentChar();

                if (char === '"') {
                    return this._parseString();
                } else if (char === '{') {
                    return this._parseObject();
                } else if (char === '[') {
                    return this._parseArray();
                } else if (char === 't') {
                    return this._parseTrue();
                } else if (char === 'f') {
                    return this._parseFalse();
                } else if (char === 'n') {
                    return this._parseNull();
                } else if (char === '-' || /\d/.test(char)) {
                    return this._parseNumber();
                } else {
                    throw new JSONParseError(`意外字符 '${char}'`, this.pos);
                }
            }

            _parseString() {
                if (this._currentChar() !== '"') {
                    throw new JSONParseError('期望字符串开始引号', this.pos);
                }

                this._advance();
                let result = '';

                while (this.pos < this.length) {
                    const char = this._currentChar();

                    if (char === '"') {
                        this._advance();
                        return result;
                    } else if (char === '\\') {
                        result += this._parseEscapeSequence();
                    } else if (char.charCodeAt(0) < 32) {
                        throw new JSONParseError(`字符串中不允许控制字符 '\\u${char.charCodeAt(0).toString(16).padStart(4, '0')}'`, this.pos);
                    } else {
                        result += this._advance();
                    }
                }

                throw new JSONParseError('字符串未正确结束', this.pos);
            }

            _parseEscapeSequence() {
                if (this._currentChar() !== '\\') {
                    throw new JSONParseError('期望转义字符', this.pos);
                }

                this._advance();

                if (this.pos >= this.length) {
                    throw new JSONParseError('转义序列不完整', this.pos);
                }

                const char = this._advance();
                const escapeMap = {
                    '"': '"',
                    '\\': '\\',
                    '/': '/',
                    'b': '\b',
                    'f': '\f',
                    'n': '\n',
                    'r': '\r',
                    't': '\t'
                };

                if (char in escapeMap) {
                    return escapeMap[char];
                } else if (char === 'u') {
                    return this._parseUnicodeEscape();
                } else {
                    throw new JSONParseError(`无效的转义字符 '\\${char}'`, this.pos - 1);
                }
            }

            _parseUnicodeEscape() {
                if (this.pos + 4 > this.length) {
                    throw new JSONParseError('Unicode转义序列不完整', this.pos);
                }

                const hexDigits = this.text.substr(this.pos, 4);

                if (!/^[0-9A-Fa-f]{4}$/.test(hexDigits)) {
                    throw new JSONParseError('无效的Unicode转义序列', this.pos);
                }

                this.pos += 4;
                const codePoint = parseInt(hexDigits, 16);
                return String.fromCharCode(codePoint);
            }

            _parseObject() {
                if (this._currentChar() !== '{') {
                    throw new JSONParseError('期望对象开始大括号', this.pos);
                }

                this._advance();
                this._skipWhitespace();

                const result = {};

                if (this.pos < this.length && this._currentChar() === '}') {
                    this._advance();
                    return result;
                }

                while (true) {
                    this._skipWhitespace();

                    if (this.pos >= this.length || this._currentChar() !== '"') {
                        throw new JSONParseError('期望对象键（字符串）', this.pos);
                    }

                    const key = this._parseString();
                    this._skipWhitespace();

                    if (this.pos >= this.length || this._currentChar() !== ':') {
                        throw new JSONParseError('期望冒号', this.pos);
                    }

                    this._advance();
                    const value = this._parseValue();
                    result[key] = value;

                    this._skipWhitespace();

                    if (this.pos >= this.length) {
                        throw new JSONParseError('对象未正确结束', this.pos);
                    }

                    const char = this._currentChar();
                    if (char === '}') {
                        this._advance();
                        break;
                    } else if (char === ',') {
                        this._advance();
                        continue;
                    } else {
                        throw new JSONParseError(`对象中期望 ',' 或 '}' 但遇到 '${char}'`, this.pos);
                    }
                }

                return result;
            }

            _parseArray() {
                if (this._currentChar() !== '[') {
                    throw new JSONParseError('期望数组开始方括号', this.pos);
                }

                this._advance();
                this._skipWhitespace();

                const result = [];

                if (this.pos < this.length && this._currentChar() === ']') {
                    this._advance();
                    return result;
                }

                while (true) {
                    const value = this._parseValue();
                    result.push(value);

                    this._skipWhitespace();

                    if (this.pos >= this.length) {
                        throw new JSONParseError('数组未正确结束', this.pos);
                    }

                    const char = this._currentChar();
                    if (char === ']') {
                        this._advance();
                        break;
                    } else if (char === ',') {
                        this._advance();
                        continue;
                    } else {
                        throw new JSONParseError(`数组中期望 ',' 或 ']' 但遇到 '${char}'`, this.pos);
                    }
                }

                return result;
            }

            _parseTrue() {
                if (this.text.substr(this.pos, 4) === 'true') {
                    this.pos += 4;
                    return true;
                } else {
                    throw new JSONParseError('无效的true值', this.pos);
                }
            }

            _parseFalse() {
                if (this.text.substr(this.pos, 5) === 'false') {
                    this.pos += 5;
                    return false;
                } else {
                    throw new JSONParseError('无效的false值', this.pos);
                }
            }

            _parseNull() {
                if (this.text.substr(this.pos, 4) === 'null') {
                    this.pos += 4;
                    return null;
                } else {
                    throw new JSONParseError('无效的null值', this.pos);
                }
            }

            _parseNumber() {
                const startPos = this.pos;

                if (this._currentChar() === '-') {
                    this._advance();
                }

                if (this.pos >= this.length) {
                    throw new JSONParseError('数字不完整', this.pos);
                }

                if (this._currentChar() === '0') {
                    this._advance();
                } else if (/\d/.test(this._currentChar())) {
                    while (this.pos < this.length && /\d/.test(this._currentChar())) {
                        this._advance();
                    }
                } else {
                    throw new JSONParseError('无效的数字格式', this.pos);
                }

                let isFloat = false;

                if (this.pos < this.length && this._currentChar() === '.') {
                    isFloat = true;
                    this._advance();

                    if (this.pos >= this.length || !/\d/.test(this._currentChar())) {
                        throw new JSONParseError('小数点后必须有数字', this.pos);
                    }

                    while (this.pos < this.length && /\d/.test(this._currentChar())) {
                        this._advance();
                    }
                }

                if (this.pos < this.length && /[eE]/.test(this._currentChar())) {
                    isFloat = true;
                    this._advance();

                    if (this.pos < this.length && /[+-]/.test(this._currentChar())) {
                        this._advance();
                    }

                    if (this.pos >= this.length || !/\d/.test(this._currentChar())) {
                        throw new JSONParseError('指数必须有数字', this.pos);
                    }

                    while (this.pos < this.length && /\d/.test(this._currentChar())) {
                        this._advance();
                    }
                }

                const numberStr = this.text.substring(startPos, this.pos);

                try {
                    if (isFloat) {
                        return parseFloat(numberStr);
                    } else {
                        return parseInt(numberStr, 10);
                    }
                } catch (error) {
                    throw new JSONParseError(`无效的数字格式: ${numberStr}`, startPos);
                }
            }
        }

        // 统计数据
        let stats = {
            parseCount: 0,
            successCount: 0,
            errorCount: 0
        };

        // 示例数据
        const examples = [
            {
                name: "基本对象",
                data: `{
    "name": "张三",
    "age": 25,
    "active": true,
    "salary": 5000.50
}`
            },
            {
                name: "数组数据",
                data: `[1, 2, 3, "hello", true, null, 3.14, -42]`
            },
            {
                name: "嵌套结构",
                data: `{
    "users": [
        {"name": "Alice", "age": 30},
        {"name": "Bob", "age": 25}
    ],
    "total": 2
}`
            },
            {
                name: "复杂数据",
                data: `{
    "product": {
        "name": "智能手机",
        "brand": "TechCorp",
        "price": 2999.99,
        "available": true,
        "specs": {
            "screen": "6.1寸",
            "memory": "128GB",
            "colors": ["黑色", "白色", "蓝色"]
        },
        "reviews": [
            {
                "user": "张三",
                "rating": 5,
                "comment": "非常好用！"
            },
            {
                "user": "李四",
                "rating": 4,
                "comment": "性价比不错"
            }
        ]
    }
}`
            },
            {
                name: "Unicode字符",
                data: `{
    "message": "你好世界 🌍",
    "emoji": "😊",
    "chinese": "中文测试",
    "unicode": "\\u4e2d\\u6587",
    "mixed": "Hello 世界 🚀"
}`
            }
        ];

        // 解析JSON函数
        function parseJSON() {
            const input = document.getElementById('jsonInput').value;
            const resultDiv = document.getElementById('result');
            
            stats.parseCount++;
            updateStats();

            if (!input.trim()) {
                resultDiv.className = 'result-content error';
                resultDiv.textContent = '请输入JSON数据';
                return;
            }

            try {
                const parser = new JSONParser();
                const result = parser.parse(input);
                
                stats.successCount++;
                updateStats();
                
                resultDiv.className = 'result-content success';
                resultDiv.textContent = '✅ 解析成功！\n\n' + 
                                       '解析结果：\n' + 
                                       JSON.stringify(result, null, 2);
            } catch (error) {
                stats.errorCount++;
                updateStats();
                
                resultDiv.className = 'result-content error';
                resultDiv.textContent = '❌ 解析失败！\n\n' + 
                                       '错误信息：\n' + 
                                       error.message;
            }
        }

        // 清空所有内容
        function clearAll() {
            document.getElementById('jsonInput').value = '';
            const resultDiv = document.getElementById('result');
            resultDiv.className = 'result-content';
            resultDiv.textContent = '等待解析...';
        }

        // 格式化JSON
        function formatJSON() {
            const input = document.getElementById('jsonInput').value;
            
            if (!input.trim()) {
                alert('请先输入JSON数据');
                return;
            }

            try {
                const parser = new JSONParser();
                const result = parser.parse(input);
                document.getElementById('jsonInput').value = JSON.stringify(result, null, 2);
                
                const resultDiv = document.getElementById('result');
                resultDiv.className = 'result-content success';
                resultDiv.textContent = '✅ 格式化成功！';
            } catch (error) {
                alert('JSON格式错误，无法格式化：\n' + error.message);
            }
        }

        // 加载示例
        function loadExample(index) {
            if (index >= 0 && index < examples.length) {
                document.getElementById('jsonInput').value = examples[index].data;
                const resultDiv = document.getElementById('result');
                resultDiv.className = 'result-content';
                resultDiv.textContent = `已加载示例：${examples[index].name}`;
            }
        }

        // 更新统计数据
        function updateStats() {
            document.getElementById('parseCount').textContent = stats.parseCount;
            document.getElementById('successCount').textContent = stats.successCount;
            document.getElementById('errorCount').textContent = stats.errorCount;
        }

        // 键盘快捷键
        document.addEventListener('keydown', function(e) {
            if (e.ctrlKey && e.key === 'Enter') {
                parseJSON();
            } else if (e.ctrlKey && e.key === 'l') {
                e.preventDefault();
                clearAll();
            }
        });

        // 页面加载完成后的初始化
        document.addEventListener('DOMContentLoaded', function() {
            // 加载默认示例
            loadExample(0);
            
            // 添加输入提示
            const jsonInput = document.getElementById('jsonInput');
            jsonInput.addEventListener('input', function() {
                const resultDiv = document.getElementById('result');
                if (this.value.trim()) {
                    resultDiv.className = 'result-content';
                    resultDiv.textContent = '输入完成后点击"解析JSON"按钮...';
                }
            });
        });
    </script>
</body>
</html>